#include <iostream>
#include <vector>
#include <unordered_map>
#include <functional>
#include <memory>
#include <unistd.h>
// int8_t  int16_t  int32_t  uint8_t  uint16_t  uint32_t
// #include <cstdint>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class TimerTask
{
private:
    uint64_t _id;         // 定时器任务对象id
    uint32_t _timeout;    // 定时任务的超时时间
    bool _canceled;       // false  表示没有被取消， true 表示被取消
    TaskFunc _task_cb;    // 定时器对象要执行的定时任务
    ReleaseFunc _release; // 用于删除 TimerWheel 中保存的定时器对象信息
public:
    TimerTask(uint64_t id, uint32_t delay, const TaskFunc &cb) : _id(id), _timeout(delay), _task_cb(cb), _canceled(false) {}
    ~TimerTask()
    {
        if (_canceled == false)
            _task_cb();
        _release();
    }
    void Cancel() { _canceled = true; }
    void SetRelease(const ReleaseFunc &cb) { _release = cb; }
    uint32_t DelayTime() { return _timeout; }
};

class TimerWheel
{
private:
    // 理解下面两点很重要的：
    // 下面的 weak_ptr 和 shared_ptr 两个智能指针指向的是相同类型的对象的哦.
    // weak_ptr 指向 shared_ptr 指向的对象并不会增加对象的引用计数的，并且得通过 shared_ptr 来访问对象(weak_ptr指向对象a。a.lock() == 就得到了指向a对象的shared_ptr)
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;
    int _tick;                                      // 用来表示当前秒针，找到哪里释放哪里。释放哪里就相当于是执行哪里的任务（析构函数调用的时候就执行任务了）
    int _capacity;                                  // 半盘最大数量 --- 其实就是最大延迟时间
    std::vector<std::vector<PtrTask>> _wheel;       // 因为 shared_ptr 会增加引用计数，所以元素类型是 shared_ptr 的哦
    std::unordered_map<uint64_t, WeakTask> _timers; // 又因为 fd 多了的时候，是得管理 fd 和与之对应的 TimerTask,用 weak_ptr 是很好的哦，因为可以间接得到 shared_ptr

private:
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }

public:
    // 主营我们用的是 _capacity 来初始化 _wheel 二维数组的大小的哦，所以 _capacity 得先初始化的哦，所以声明的时候 _capacity 得在 _wheel 的前面的哦
    TimerWheel() : _capacity(60), _tick(0), _wheel(_capacity) {}
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb)
    {
        PtrTask pt(new TimerTask(id, delay, cb));
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
    }
    // 刷新/延迟定时任务
    void TimerRefresh(uint64_t id)
    {
        // 通过保存的定时器对象的 weak_ptr 构造一个 shared_ptr 出来，添加到轮子中
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;                     // 没找着定时任务，没法刷新，没法延迟
        PtrTask pt = it->second.lock(); // lock 获取weak_ptr管理的对象对应的shares_ptr
        int delay = pt->DelayTime();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }
    // 下面的取消定时任务的方式得注意不能直接从 _wheel 数组中移除的哦(二维数组不好操作的)
    void TimerCancel(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;                     // 没找着定时任务，没法刷新，没法延迟
        PtrTask pt = it->second.lock(); // lock 获取weak_ptr管理的对象对应的shares_ptr
        if (pt)
            pt->Cancel();
    }
    // 这个函数就相当于是每秒钟被执行一次，相当于秒针向后走了一步
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear(); // 清空指定位置的数组，就会把数组中保存的所有管理定时器对象的shares_ptr释放掉
    }
};

class Test
{
public:
    Test() { std::cout << "构造" << std::endl; }
    ~Test() { std::cout << "析构" << std::endl; }
};

void DelTest(Test *t)
{
    delete t;
}

int main(void)
{
    TimerWheel tw;

    Test *t = new Test();

    tw.TimerAdd(888, 5, std::bind(DelTest, t));

    for (int i = 0; i < 5; i++)
    {
        sleep(1);
        // tw.TimerRefresh(888); // 刷新定时任务
        tw.RunTimerTask(); // 向后移动秒针
        std::cout << "刷新了一下定时任务，重新需要5s钟后才会销毁\n";
    }
    // tw.TimerCancel(888);
    while (1)
    {
        sleep(1);
        std::cout << "----------------------\n";
        tw.RunTimerTask(); // 向后移动秒针
    }

    return 0;
}